package com.functest.jpwise.deprecated;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;

import com.functest.jpwise.core.ParameterValue;
import com.functest.jpwise.core.SimpleValue;
import junit.framework.Assert;



/** Represents a factory that creates parameter combinations (i.e., test cases)
 * for parameterized JUnit tests.
 * 
 * @author Jeremy Reeder
 * @version 2011-11-22
 * @since 2011-10-25 */
public abstract class ParameterFactory {
	private int possibleCombinationCount = 1;

	/** Correlates parameter-value IDs (to be used internally) with parameter
	 * values (to be passed into a parameterized test). */
	protected Map<ParameterValue, Object> idToParameterMap = new HashMap<>();

	/** Contains, for each test parameter, a Set of IDs corresponding to possible
	 * values. */
	protected List<Set<ParameterValue>> orderedListOfParameterIdSets = new ArrayList<>();

	/** Sets the possible values for each test parameter. 
	 * @param valueCollections one or more Collections of parameter values. */
	public void setValuesToTestForEachParameter(
			Collection<?>... valueCollections) {
		int globallyUniqueValueIndex = 0;
		for (Collection<?> valueCollection : valueCollections) {
			Assert.assertFalse(
				"Parameter has empty value-set. All parameters must have values to test.",
				valueCollection.isEmpty()
			);
			possibleCombinationCount *= valueCollection.size();
			final Set<ParameterValue> parameterIdSet = new HashSet<>();
			for (Object value : valueCollection) {
				final ParameterValue parameterId =  SimpleValue.of(globallyUniqueValueIndex);
                globallyUniqueValueIndex++;
                parameterIdSet.add(parameterId);
				idToParameterMap.put(parameterId, value);
			}
			orderedListOfParameterIdSets.add(parameterIdSet);
		}

	}

	/** Sets the possible values for each test parameter.
	 * @param valueArrays
	 * one or more arrays of parameter values. */
	public void setValuesToTestForEachParameter(Object[]... valueArrays) {
		final int parameterCount = valueArrays.length;
		Set[] valueSets = new Set[parameterCount];
		for (int i = 0; i < parameterCount; i++) {
			valueSets[i] = new HashSet<>(Arrays.asList(valueArrays[i]));
		}
		setValuesToTestForEachParameter(valueSets);
	}

	/** Creates a list of parameter-ID arrays that represent arrays of parameter
	 * combinations.
	 * @return list of arrays of parameter IDs, where each ID is mapped to a parameter value */
	protected abstract List<ParameterValue[]> createListOfParameterIdCombinations();

	/** Creates a list of parameter arrays for use in a parameterized jUnit test.
	 * In a parameterized test, the method annotated {@link #@Parameterized.Parameters} should return this value. 
	 * @return list of Object arrays, where each Object is a test parameter */
	public List<Object[]> createListOfParameterCombinations() {
		final List<Object[]> listOfParameterArrays = new ArrayList<Object[]>();
		for (ParameterValue[] parameterIds : createListOfParameterIdCombinations()) {
			final int parameterCount = parameterIds.length;
			Object[] parameters = new Object[parameterCount];
			for (int i = 0; i < parameterCount; i++)
				parameters[i] = idToParameterMap.get(parameterIds[i]);
			listOfParameterArrays.add(parameters);
		}
		System.out.printf(
			"Created parameter combinations for %d test cases (of %d possibilities).%n",
			listOfParameterArrays.size(), possibleCombinationCount
		);
		Assert.assertFalse("Generated an empty list of parameter combinations.", listOfParameterArrays.isEmpty());
		return listOfParameterArrays;
	}
}
